/*  File Name	: DirectoryLogic.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-11-30
 *  Description:
 */

#include "DirectoryMonitor.h"


void DirectoryMonitor::collection_info(void)
{

}

int DirectoryMonitor::respond_succ_to_client(int id,int cmd,MessageBlock *mb)
{
	MessageBlock *mb_send = NULL;
	if(this->msg_pool()->pop(mb_send)==0)
	{
		*mb_send << id << cmd << 0 ;
		if(NULL!=mb)
		{
			mb_send->write(mb->rd_ptr(),mb->data_len());
		}
		this->respond_mb_push(mb_send);
	}
	return 0;
}

int DirectoryMonitor::respond_error_to_client(int id,int cmd,int error,MessageBlock *mb)
{
	MessageBlock *mb_send = NULL;
	if(this->msg_pool()->pop(mb_send)==0)
	{
		*mb_send << id << cmd << error;
		if(NULL!=mb)
		{
			mb_send->write(mb->rd_ptr(),mb->data_len());
		}
		this->respond_mb_push(mb_send);
	}
	return 0;
}

int DirectoryMonitor::handle_close(DirectoryService *ds)
{
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	std::string key = this->key(ds->peer_addr(),ds->peer_port());
	if(this->web_map_.find(key)!=this->web_map_.end())
	{
		this->web_map_.erase(key);
	}
	return super::handle_close(ds);
}

int DirectoryMonitor::gate_login(DirectoryService *ds,MessageBlock *mb)
{
	if(NULL==ds|| NULL==mb)
	{
		return 0;
	}
	int gate_id=0,game_type=0;
	std::string game_name;
	*mb >> game_type>> game_name >> gate_id;

	LOG((INFO_LOG,"DirectoryMonitor::gate_login[%s:%d] [type:%d][gate:%d][name:%s]",
			ds->peer_addr(),ds->peer_port(),game_type,gate_id,game_name.c_str()));

	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	if(game_type<1 || game_type>=(int)this->game_vec_.size())
	{
		return 0;
	}

	GameInfo &game = this->game_vec_[game_type-1];
	game.name = game_name;
	GateWayMap &map = game.svr_map;
	GateWayMap::iterator iter=map.find(gate_id);
	if(iter!=map.end())
	{
		return this->respond_error_to_client(ds->unique_id(),
							RETURN_DIRCSERVER_LOGIN,ERROR_DIRC_REGISTER_GATEID);
	}
	ds->server_id(gate_id);
	ds->game_type(game_type);

	GateWay *info = new GateWay();
	info->game_type = game_type;
	info->game_name = game_name;
	info->gate_id = gate_id;
	info->ds = ds;
	info->ip = ds->peer_addr();
	info->port = ds->peer_port();
	map.insert(std::pair<int,GateWay*>(gate_id,info));
	return this->respond_succ_to_client(ds->unique_id(),RETURN_DIRCSERVER_LOGIN);
}

int DirectoryMonitor::gate_logout(DirectoryService *ds,MessageBlock *mb)
{
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	GateWayMap &map = this->game_vec_[ds->game_type()-1].svr_map;
	GateWayMap::iterator iter = map.find(ds->server_id());
	if (iter != map.end())
	{
		//notify
		DELETE(iter->second);
		map.erase(iter->first);
	}
	return 0;
}

int DirectoryMonitor::gate_update(DirectoryService *ds,MessageBlock *mb)
{
	if(NULL==ds|| NULL==mb)
	{
		return 0;
	}
	int gate_id=0,player_count=0;
	*mb >> gate_id >> player_count;

	LOG((INFO_LOG,"DirectoryMonitor::gate_update[%s:%d] [type:%d][gate:%d][player:%d]",
			ds->peer_addr(),ds->peer_port(),ds->game_type(),gate_id,player_count));

	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	GameInfo &game = this->game_vec_[ds->game_type()-1];
	game.type = ds->game_type();

	GateWayMap &map = game.svr_map;
	GateWayMap::iterator iter = map.find(gate_id);
	if (iter != map.end())
	{
		MessageBlock mb_send(2048);
		mb_send << 0;
		int count = 0;

		GateWay *gate = iter->second;
		game.total_player +=(player_count-gate->total_player);
		gate->total_player = player_count;

		std::map<int,Room> &room_map =gate->room_map;
		int size = 0;
		*mb >> size;
		for(int i=0;i<size;i++)
		{
			Room room;
			*mb >> room.room_id >> room.limit_member
				>> room.member >> room.max_chips >> room.min_chips;
			if(room.room_id<=0)
			{
				continue;
			}
			std::map<int,Room>::iterator room_iter= room_map.find(room.room_id);
			if(room_iter!=room_map.end())
			{
				room_iter->second = room;
			}
			else
			{
				room_map.insert(std::pair<int,Room>(room.room_id,room));
			}
			count++;
			mb_send << room.room_id;
		}
		::memcpy(mb_send.base_ptr(),&count,sizeof(int));
		return this->respond_succ_to_client(ds->unique_id(),RETURN_DIRCSERVER_UPDATE,&mb_send);
	}
	return 0;
}

int DirectoryMonitor::client_get_list(DirectoryService *ds,MessageBlock *mb)
{
	int game_type = 0;
	*mb >> game_type;
	if(game_type<1 || game_type >=(int)this->game_vec_.size())
	{
		return 0;
	}

	LOG((INFO_LOG,"DirectoryMonitor::client_get_list [%s:%d]"
			,ds->peer_addr(),ds->peer_port()));

	MessageBlock mb_send(4096);
	this->make_up_room_info(game_type,&mb_send);

	return this->respond_succ_to_client(ds->unique_id(),
			RETURN_DIRCSERVER_GET_INFO,&mb_send);
}

int DirectoryMonitor::make_up_room_info(int type,MessageBlock *mb)
{
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	GameInfo &game = this->game_vec_[type - 1];
	GateWayMap &map = game.svr_map;

	int count = 0;
	char *p = mb->wr_ptr();
	*mb << 0;
	GateWayMap::iterator iter = map.begin();
	for (; iter != map.end(); iter++)
	{
		GateWay *gate = iter->second;
		if (NULL == gate)
		{
			continue;
		}
		RoomMap::iterator room_iter = gate->room_map.begin();
		for (; room_iter != gate->room_map.end(); room_iter++)
		{
			Room &room = room_iter->second;
			*mb << gate->gate_id << gate->ip << gate->port << room.room_id
					<< room.limit_member << room.member << room.min_chips
					<< room.max_chips;
			count ++;
		}
	}
	memcpy(p,&count,sizeof(int));
	return 0;
}

int DirectoryMonitor::register_to_web(void)
{
	MessageBlock mb_send(4096);
	mb_send << 0;
	this->make_up_game_info(&mb_send);

	const Json::Value &web_cfg = this->cfg()["webserver"];
	for(int i=0;i<(int)web_cfg.size();i++)
	{
		std::string ip = web_cfg[i][0u].asString();
		int port = web_cfg[i][1u].asInt();

		DirectoryService *ds = this->find_web(ip,port);
		if(NULL==ds && (ds=this->new_web_conn(ip,port))==NULL)
		{
			continue;
		}
		this->respond_succ_to_client(ds->unique_id(),STC_GAMEINFO_TO_WEB,&mb_send);
	}
	return 0;
}

int DirectoryMonitor::make_up_game_info(MessageBlock *mb)
{
	int count = 0;
	int port = this->cfg()["port"].asInt();
	std::string ip = this->cfg()["ip"].asString();

	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);

	for(int i=0;i<(int)this->game_vec_.size();i++)
	{
		GameInfo &game = this->game_vec_[i];
		GateWayMap &map = game.svr_map;
		if(map.size()<=0)
		{
			continue;
		}
		count ++;
		*mb << game.type << game.name << game.total_player << ip << port;
	}
	return 0;
}

std::string DirectoryMonitor::key(std::string ip,int port)
{
	char p[20]={0};
	sprintf(p,"%d",port);
	return (ip+std::string(p));
}

DirectoryService* DirectoryMonitor::find_web(std::string ip,int port)
{
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,NULL);
	std::string key = this->key(ip,port);
	WebMap::iterator iter=this->web_map_.find(key);
	if(iter==this->web_map_.end() || iter->second==NULL)
	{
		if(iter->second==NULL)
		{
			this->web_map_.erase(key);
		}
		return NULL;
	}
	return iter->second;
}

DirectoryService* DirectoryMonitor::new_web_conn(std::string ip,int port)
{
	std::string key = this->key(ip,port);
	DirectoryService *ds = NULL;

	if(this->connector_->connect(ip,port,ds)<0)
	{
		LOG((ERROR_LOG,"DirectoryMonitor::new_web_conn connect web [%s:%d] failed",ip.c_str(),port));
		if(NULL!=ds)
		{
			ds->handle_close();
		}
		return NULL;
	}
	LOG((INFO_LOG,"DirectoryMonitor::new_web_conn connect web [%s:%d] succ",ip.c_str(),port));
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,NULL);
	this->web_map_.insert(std::pair<std::string,DirectoryService*>(key,ds));
	return ds;
}
